package trackClustering.example.behavior;

import trackClustering.example.entity.TrajectoryPoint;
import trackClustering.example.spatial.TrajectoryProcessorByDbscan;

import java.util.*;
import java.util.stream.Collectors;

import static trackClustering.example.spatial.TrajectoryProcessorByDbscan.calculateDistance;
import static trackClustering.example.spatial.TrajectoryProcessorByDbscan.computeQuantile;

public class TrajectoryProcessBySpeed {
    public static int globalBehaviorClusterId = 1;
    // 全局行为簇ID计数器
    boolean autoDetermineK;

    private double speedEps;
    // DBSCAN邻域半径
    private int minPts;
    // DBSCAN密度阈值
    private final AlgorithmType algorithm;

    public enum AlgorithmType {
        KMEANS, DBSCAN
    }

    public TrajectoryProcessBySpeed(AlgorithmType algorithm,
                                    boolean autoDetermineK,
                                    double speedEps,
                                    int minPts) {
        this.algorithm = algorithm;
        this.autoDetermineK = autoDetermineK;
        this.speedEps = speedEps;
        this.minPts = minPts;
    }

    // 速度聚类主方法
//    public Map<Integer, Map<Integer, List<TrajectoryPoint>>> clusterBySpeed(
//            Map<Integer, List<TrajectoryPoint>> spatialClusters) {
//        Map<Integer, Map<Integer, List<TrajectoryPoint>>> result = new HashMap<>();
//
//        for (Map.Entry<Integer, List<TrajectoryPoint>> entry : spatialClusters.entrySet()) {
//            int spatialId = entry.getKey();
//            List<TrajectoryPoint> points = entry.getValue();
//
//            if (points.size() < minPts) {
//                continue; // 过滤小簇
//            }
//
//            // 提取标准化速度特征
//            List<Double> normalizedSpeeds = extractAndNormalizeSpeeds(points);
//
//            // 根据算法类型执行聚类
//            List<List<Integer>> clusterIndices;
//            if (algorithm == AlgorithmType.KMEANS) {
//                int k = autoDetermineK(normalizedSpeeds);
//                clusterIndices = kmeansCluster(normalizedSpeeds, k);
//                // 传递k值
//            } else {
//                clusterIndices = dbscanCluster(normalizedSpeeds);
//            }
//
//            // 构建结果映射
//            Map<Integer, List<TrajectoryPoint>> speedClusters = new HashMap<>();
//            for (int i = 0; i < clusterIndices.size(); i++) {
//                List<TrajectoryPoint> clusterPoints = new ArrayList<>();
//                for (int index : clusterIndices.get(i)) {
//                    clusterPoints.add(points.get(index));
//                }
//                speedClusters.put(globalBehaviorClusterId++, clusterPoints);
//            }
//
//            result.put(spatialId, speedClusters);
//        }
//        return result;
//    }
    public Map<Integer, Map<Integer, List<TrajectoryPoint>>> clusterBySpeed(
            Map<Integer, List<TrajectoryPoint>> spatialClusters) {
        Map<Integer, Map<Integer, List<TrajectoryPoint>>> result = new HashMap<>();

        for (Map.Entry<Integer, List<TrajectoryPoint>> entry : spatialClusters.entrySet()) {
            int spatialId = entry.getKey();
            List<TrajectoryPoint> points = entry.getValue();

            if (points.size() < minPts) {
                continue; // 过滤小簇
            }

            // 提取标准化速度特征
            List<Double> normalizedSpeeds = extractAndNormalizeSpeeds(points);

            // 执行聚类
            List<List<Integer>> clusterIndices;
            if (algorithm == AlgorithmType.KMEANS) {
                int k = autoDetermineK(normalizedSpeeds);
                clusterIndices = kmeansCluster(normalizedSpeeds, k);
            } else {
                clusterIndices = dbscanCluster(normalizedSpeeds);
            }

            // 收集原始簇
            List<List<TrajectoryPoint>> allClusters = new ArrayList<>();
            for (List<Integer> indices : clusterIndices) {
                List<TrajectoryPoint> clusterPoints = new ArrayList<>();
                for (int index : indices) {
                    clusterPoints.add(points.get(index));
                }
                allClusters.add(clusterPoints);
            }

            // 分离有效/无效簇
            List<List<TrajectoryPoint>> validClusters = new ArrayList<>();
            List<List<TrajectoryPoint>> invalidClusters = new ArrayList<>();
            int spatialSize = points.size();
            for (List<TrajectoryPoint> cluster : allClusters) {
                int clusterSize = cluster.size();
                if (clusterSize > spatialSize * 0.3 && clusterSize > 10) {
                    validClusters.add(cluster);
                } else {
                    invalidClusters.add(cluster);
                }
            }

            // 处理无效簇
            if (validClusters.isEmpty()) {
                // 全部无效则合并为一个簇
                validClusters.clear();
                validClusters.add(points);
                // 直接使用整个空间簇
            } else {
                // 合并无效簇到最近有效簇的原有逻辑保持不变
                List<Double> validCenters = new ArrayList<>();
                for (List<TrajectoryPoint> cluster : validClusters) {
                    double meanSpeed = cluster.stream()
                            .mapToDouble(TrajectoryPoint::getHorizontalSpeed)
                            .average()
                            .orElse(0);
                    validCenters.add(meanSpeed);
                }

                for (List<TrajectoryPoint> invalidCluster : invalidClusters) {
                // 修改分配逻辑，增加空间距离权重
                    for (TrajectoryPoint point : invalidCluster) {
                        double pointSpeed = point.getHorizontalSpeed();
                        // 新增空间坐标获取
                        double[] pointLocation = {
                                point.getEasting(),
                                point.getNorthing(),
                                point.getHeight()
                        };
                        double minTotalDist = Double.MAX_VALUE;
                        int bestClusterIndex = 0;

                        for (int i = 0; i < validClusters.size(); i++) {
                            List<TrajectoryPoint> validCluster = validClusters.get(i);
                            int clusterSize = validCluster.size();
                            // 计算速度差异
                            double speedDist = Math.abs(pointSpeed - validCenters.get(i));
                            // 计算空间距离（取簇中心或最近点）
                            double spaceDist = calculateMinSpaceDistance(pointLocation, validCluster);

                            // 综合权重计算（可调整权重参数）
                            double totalDist = 0.7 * speedDist + 0.3 * spaceDist;

                            if (totalDist < minTotalDist) {
                                minTotalDist = totalDist;
                                bestClusterIndex = i;
                            }
                        }
                        validClusters.get(bestClusterIndex).add(point);
                    }
                }

            }

            // 构建结果
            Map<Integer, List<TrajectoryPoint>> speedClusters = new HashMap<>();
            for (List<TrajectoryPoint> cluster : validClusters) {
                speedClusters.put(globalBehaviorClusterId++, new ArrayList<>(cluster));
            }

            result.put(spatialId, speedClusters);
        }
        return result;
    }


    // 特征提取与标准化
    private List<Double> extractAndNormalizeSpeeds(List<TrajectoryPoint> points) {
        List<Double> speeds = points.stream()
                .mapToDouble(TrajectoryPoint::getHorizontalSpeed)
                .boxed()
                .collect(Collectors.toList());

        double mean = calculateMean(speeds);
        double std = calculateStd(speeds);

        return speeds.stream()
                .map(s -> (s - mean) / Math.max(std, 1e-6))
                .collect(Collectors.toList());
    }

    // K-means实现
    private static List<List<Integer>> kmeansCluster(List<Double> normalizedSpeeds, int k) {
        // 初始化质心（随机选择k个点）
        List<Double> centroids = new ArrayList<>();
        Random rand = new Random();
        for (int i = 0; i < k; i++) {
            centroids.add(normalizedSpeeds.get(rand.nextInt(normalizedSpeeds.size())));
        }

        // 迭代聚类
        List<List<Integer>> clusters = new ArrayList<>();
        boolean converged = false;
        while (!converged) {
            clusters = new ArrayList<>();
            for (int i = 0; i < k; i++) {
                clusters.add(new ArrayList<>());
            }

            // 分配簇
            for (int i = 0; i < normalizedSpeeds.size(); i++) {
                double minDist = Double.MAX_VALUE;
                int assignedCluster = 0;
                for (int j = 0; j < centroids.size(); j++) {
                    double dist = Math.abs(normalizedSpeeds.get(i) - centroids.get(j));
                    if (dist < minDist) {
                        minDist = dist;
                        assignedCluster = j;
                    }
                }
                clusters.get(assignedCluster).add(i);
            }

            // 更新质心
            List<Double> newCentroids = new ArrayList<>();
            for (List<Integer> cluster : clusters) {
                double sum = 0;
                for (int idx : cluster) {
                    sum += normalizedSpeeds.get(idx);
                }
                newCentroids.add(sum / cluster.size());
            }

            // 判断收敛
            converged = centroids.equals(newCentroids);
            centroids = newCentroids;
        }

        return clusters;
    }

    // DBSCAN实现（单维优化版）
    private List<List<Integer>> dbscanCluster(List<Double> normalizedSpeeds) {
        List<List<Integer>> clusters = new ArrayList<>();
        boolean[] visited = new boolean[normalizedSpeeds.size()];
        int clusterId = 0;

        for (int i = 0; i < normalizedSpeeds.size(); i++) {
            if (!visited[i]) {
                visited[i] = true;
                List<Integer> neighbors = getNeighbors(i, normalizedSpeeds);
                if (neighbors.size() < minPts) {
                    continue; // 噪声点
                }

                clusterId++;
                clusters.add(new ArrayList<>());
                clusters.get(clusterId - 1).addAll(neighbors);
                for (int neighbor : neighbors) {
                    visited[neighbor] = true;
                }

                // 扩展簇
                for (int neighbor : neighbors) {
                    List<Integer> neighborNeighbors = getNeighbors(neighbor, normalizedSpeeds);
                    if (neighborNeighbors.size() >= minPts) {
                        for (int idx : neighborNeighbors) {
                            if (!visited[idx]) {
                                visited[idx] = true;
                                clusters.get(clusterId - 1).add(idx);
                            }
                        }
                    }
                }
            }
        }
        return clusters;
    }

    // 获取邻近点（单维优化）
    private List<Integer> getNeighbors(int index, List<Double> speeds) {
        List<Integer> neighbors = new ArrayList<>();
        for (int i = 0; i < speeds.size(); i++) {
            if (Math.abs(speeds.get(index) - speeds.get(i)) <= speedEps) {
                neighbors.add(i);
            }
        }
        return neighbors;
    }

    // 参数调优方法（示例）
//    private static int autoDetermineK(List<Double> speeds) {
//        int bestK = 0;
//        double minWCSS = Double.MAX_VALUE;
//
//        for (int k = 1; k <= 5; k++) {
//            // 测试k=1到5
//            List<List<Integer>> clusters = kmeansCluster(speeds, k);
//            double wcss = 0;
//            for (List<Integer> cluster : clusters) {
//                double centroid = speeds.stream()
//                        .mapToDouble(s -> s)
//                        .average()
//                        .orElse(0);
//                for (int idx : cluster) {
//                    wcss += Math.pow(speeds.get(idx) - centroid, 2);
//                }
//            }
//            if (wcss < minWCSS) {
//                minWCSS = wcss;
//                bestK = k;
//            }
//        }
//        return bestK;
//    }

    private static int autoDetermineK(List<Double> speeds) {
        int bestK = 0;
        double minWCSS = Double.MAX_VALUE;
        int maxKToTest = 3;

        for (int k = 1; k <= maxKToTest; k++) {
            double totalWCSS = 0;
            // 运行K-means多次取平均（此处简化为运行一次）
            List<List<Integer>> clusters = kmeansCluster(speeds, k);

            for (List<Integer> clusterIndices : clusters) {
                if (clusterIndices.isEmpty()) {
                    continue;
                }
                // 避免空簇

                // 计算该簇的质心（平均值）
                double centroid = clusterIndices.stream()
                        .mapToDouble(idx -> speeds.get(idx))
                        .average()
                        .orElse(0);

                // 计算该簇的WCSS
                double clusterWCSS = clusterIndices.stream()
                        .mapToDouble(idx -> Math.pow(speeds.get(idx) - centroid, 2))
                        .sum();
                totalWCSS += clusterWCSS;
            }

            if (totalWCSS < minWCSS) {
                minWCSS = totalWCSS;
                bestK = k;
            }
        }
        return bestK;
    }

    // 统计方法
    private double calculateMean(List<? extends Number> values) {
        return values.stream()
                .mapToDouble(Number::doubleValue)
                .average()
                .orElse(0);
    }

    private double calculateStd(List<? extends Number> values) {
        double mean = calculateMean(values);
        double sum = 0;
        for (Number v : values) {
            sum += Math.pow(v.doubleValue() - mean, 2);
        }
        return Math.sqrt(sum / (values.size() - 1));
    }
    private double calculateMinSpaceDistance(double[] pointLocation, List<TrajectoryPoint> cluster) {
        double minDist = Double.MAX_VALUE;
        double pointEasting = pointLocation[0]; // 假设 pointLocation[0] 是东距（Easting）
        double pointNorthing = pointLocation[1]; // pointLocation[1] 是北距（Northing）
        double pointHeight = pointLocation[2]; // 添加高度维度（如果轨迹点包含高度）

        for (TrajectoryPoint p : cluster) {
            double clusterEasting = p.getEasting();
            double clusterNorthing = p.getNorthing();
            double clusterHeight = p.getHeight();

            // 使用静态方法计算三维距离
            double dist = TrajectoryProcessorByDbscan.calculateDistance(
                    new TrajectoryPoint(pointEasting, pointNorthing, pointHeight),
                    new TrajectoryPoint(clusterEasting, clusterNorthing, clusterHeight)
            );

            if (dist < minDist) {
                minDist = dist;
            }
        }
        return minDist;
    }

}
